package header

import (
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"strconv"
	"strings"
	"udp_tcp_client/sip/header/common"
	"udp_tcp_client/util"
)

type Header struct {
	Via           ViaList     // (RFC3261-8.1.1.7) 请求路径
	From          UserDomain  // (RFC3261-8.1.1.3) 请求的原始发起者
	To            UserDomain  // (RFC3261-8.1.1.2) 请求的原始到达者
	CallID        string      // (RFC3261-8.1.1.4) 唯一标志
	CSeq          CSeq        // (RFC3261-8.1.1.5) 命令序列号
	MaxForwards   MaxForwards // (RFC3261-8.1.1.6) 最大转发数量限制
	ContentLength int         // 正文长度

	ContentType     string      // (可选) 正文格式描述
	Contact         *UserIpPort // (可选) (RFC3261-8.1.1.8) 直接访问方式
	Expires         Expires     // (可选) 消息或内容过期时间
	Route           Route       // (可选) 请求的路由表
	RecordRoute     RecordRoute // (可选) 后续消息流处理的服务器列表
	UserAgent       string      // (可选) UAC的信息
	Authorization   string      // (可选) 用户认证信息
	WWWAuthenticate string      // (可选) 支持的认证方式和适用realm的参数的拒绝原因
	UnsupportLines  []string    // 暂不支持的行
	Reason          string      //备注
	Subject         string
}

func NewHeader(via ViaList, from UserDomain, to UserDomain, contact *UserIpPort, callID string, cSeq CSeq, maxForwards MaxForwards) (Header, error) {
	h := Header{}
	h.Via = via
	h.From = from
	h.To = to
	h.Contact = contact
	h.CallID = callID
	h.CSeq = cSeq
	h.MaxForwards = maxForwards
	return h, nil
}

func (header *Header) AddSubject(subject string) {
	header.Subject = subject
}

func (header *Header) AddUserAgent(userAgent string) {
	header.UserAgent = userAgent
}

func (header *Header) AddReason(reason string) {
	header.Reason = reason
}

func (header *Header) AddContact(user *UserIpPort) {
	header.Contact = user
}

func (header *Header) RemoveContentType() {
	header.ContentType = ""
}

func (header *Header) RemoveExpires() {
	header.Expires = Expires{}
}

func (header *Header) RemoveContact() {
	header.Contact = nil
}
func (header *Header) RemoveUserAgent() {
	header.UserAgent = ""
}

func (header *Header) AddContactWithDetail(username string, ip string, port int) {
	userIpPort := UserIpPort{}
	uri := common.URIIpPort{}
	uri.Username = username
	uri.IP = ip
	uri.Port = port
	uri.Scheme = util.SchemeSip
	userIpPort.URI = uri
	header.Contact = &userIpPort
}

func (header *Header) AddWWWAuthenticate() {
	builder := strings.Builder{}
	builder.WriteString(util.Digest + util.BLANK)                                                                              //注明为摘要算法
	builder.WriteString(util.Realm + util.EQUAL + util.BACKSLASH + util.Conf.Sip.Domain + util.BACKSLASH)                      //域名
	builder.WriteString(util.COMMA + util.Nonce + util.EQUAL + util.BACKSLASH + util.RandomUUidWithoutDash() + util.BACKSLASH) //随机key
	builder.WriteString(util.COMMA + util.Algorithm + util.EQUAL + util.Conf.Sip.Algorithm)                                    //摘要算法类型
	builder.WriteString(util.COMMA + util.Qop + util.EQUAL + util.BACKSLASH + util.Conf.Sip.Qop + util.BACKSLASH)              //“auth”表示鉴别方式；“auth-int”表示鉴别保护的完整性。
	header.WWWAuthenticate = builder.String()
}

func (header *Header) AddAuthorization(WWWAuthenticate string, username string, password string, method string) error {
	digestMap := header.HandleAuthorization(WWWAuthenticate)
	//cnonce := util.RandomUUidWithoutDash()
	//(*digestMap)[util.CNonce] = cnonce
	(*digestMap)[util.UserName] = username
	(*digestMap)[util.URI] = header.To.URI.String()
	response := header.GetAuthorizationResponse(digestMap, password, method)

	builder := strings.Builder{}
	builder.WriteString(util.Digest + util.BLANK) //注明为摘要算法
	builder.WriteString(util.UserName + util.EQUAL + util.BACKSLASH + (*digestMap)[util.UserName] + util.BACKSLASH)
	//builder.WriteString(util.COMMA + util.Realm + util.EQUAL + util.BACKSLASH + util.Conf.Sip.Domain + util.BACKSLASH)     //域名
	builder.WriteString(util.COMMA + util.Realm + util.EQUAL + util.BACKSLASH + (*digestMap)[util.Realm] + util.BACKSLASH) //域名
	builder.WriteString(util.COMMA + util.Nonce + util.EQUAL + util.BACKSLASH + (*digestMap)[util.Nonce] + util.BACKSLASH) //服务端随机key
	builder.WriteString(util.COMMA + util.URI + util.EQUAL + util.BACKSLASH + header.To.URI.String() + util.BACKSLASH)     //服务端uri
	builder.WriteString(util.COMMA + util.Response + util.EQUAL + util.BACKSLASH + response + util.BACKSLASH)              //response加密秘钥
	//builder.WriteString(util.COMMA + util.CNonce + util.EQUAL + util.BACKSLASH + cnonce + util.BACKSLASH)                  //客户端随机key
	//builder.WriteString(util.COMMA + util.Nc + util.EQUAL + util.BACKSLASH + util.NcFirst + util.BACKSLASH)                //计数
	builder.WriteString(util.COMMA + util.Algorithm + util.EQUAL + util.Conf.Sip.Algorithm) //摘要算法类型
	//builder.WriteString(util.COMMA + util.Qop + util.EQUAL + util.BACKSLASH + util.Conf.Sip.Qop + util.BACKSLASH)          //“auth”表示鉴别方式；“auth-int”表示鉴别保护的完整性。
	header.Authorization = builder.String()
	return nil
}

func (header *Header) HandleAuthorization(s string) (result *map[string]string) {
	digestMap := make(map[string]string)
	s = strings.Replace(s, util.Digest+util.BLANK, "", -1)
	authenticateArray := strings.Split(s, util.COMMA)
	for _, s := range authenticateArray {
		paramArray := strings.Split(s, util.EQUAL)
		digestMap[strings.TrimSpace(paramArray[0])] = strings.TrimSpace(strings.Replace(paramArray[1], util.BACKSLASH, "", -1))
	}
	return &digestMap
}

func (header *Header) GetAuthorizationResponse(digestMap *map[string]string, platformPass string, method string) (response string) {
	ha1 := (*digestMap)[util.UserName] + util.COLON + (*digestMap)[util.Realm] + util.COLON + platformPass
	ha1Md5 := util.Md5(ha1)

	ha2 := method + util.COLON + (*digestMap)[util.URI]
	ha2Md5 := util.Md5(ha2)

	sb := strings.Builder{}
	sb.WriteString(ha1Md5)
	sb.WriteString(util.COLON + (*digestMap)[util.Nonce])

	nc := (*digestMap)[util.Nc]
	cnonce := (*digestMap)[util.CNonce]
	qop := (*digestMap)[util.Qop]

	if qop == "auth" && nc != "" && cnonce != "" {
		sb.WriteString(util.COLON + nc)
		sb.WriteString(util.COLON + cnonce)
		sb.WriteString(util.COLON + qop)
	}
	sb.WriteString(util.COLON + ha2Md5)

	response = util.Md5(sb.String())

	return
}

func (header *Header) CheckAuthorization(authorization string, method string) (result bool) {
	digestMap := header.HandleAuthorization(authorization)
	response := header.GetAuthorizationResponse(digestMap, util.Conf.Sip.Password, method)
	return response == (*digestMap)[util.Response]
}

func (header *Header) AddContentType(contentType string) {
	header.ContentType = contentType
}

// 设置To的标签为From标签
func (header *Header) UpdateToTagWithFromTag() {
	if v, e := header.From.Arguments.Get(util.ArgTag); e == nil {
		header.To.Arguments.Set(util.ArgTag, v)
	}
}

// 解析消息头的单个行
func (header *Header) Parse(line string) (err error) {
	// 解析冒号的位置
	keyPosition := strings.Index(line, util.COLON)
	if keyPosition == -1 {
		err = errors.New("sip: message header line no colon")
		return
	}
	// 解析key和value并设置到结果中
	key := strings.ToLower(strings.TrimSpace(line[:keyPosition]))
	value := strings.TrimSpace(line[keyPosition+1:])
	switch key {
	case HeaderFieldVia.LowerName(), HeaderFieldVia.Abbr:
		err = header.Via.AddString(value)
	case HeaderFieldFrom.LowerName(), HeaderFieldFrom.Abbr:
		header.From, err = parseUserDomain(value)
	case HeaderFieldTo.LowerName(), HeaderFieldTo.Abbr:
		header.To, err = parseUserDomain(value)
	case HeaderFieldCallID.LowerName(), HeaderFieldCallID.Abbr:
		header.CallID = value
	case HeaderFieldCSeq.LowerName(), HeaderFieldCSeq.Abbr:
		header.CSeq, err = parseCSeq(value)
	case HeaderFieldMaxForwards.LowerName(), HeaderFieldMaxForwards.Abbr:
		header.MaxForwards, err = parseMaxForwards(value)
	case HeaderFieldContentLength.LowerName(), HeaderFieldContentLength.Abbr:
		header.ContentLength, err = strconv.Atoi(value)
	case HeaderFieldContentType.LowerName(), HeaderFieldContentType.Abbr:
		header.ContentType = value
	case HeaderFieldContact.LowerName(), HeaderFieldContact.Abbr:
		if contact, e := parseUserIpPort(value); e != nil {
			err = e
		} else {
			header.Contact = &contact
		}
	case HeaderFieldExpires.LowerName(), HeaderFieldExpires.Abbr:
		header.Expires, err = parseExpires(value)
	case HeaderFieldRoute.LowerName(), HeaderFieldRoute.Abbr:
		header.Route, err = parseRoute(value, header.Route)
	case HeaderFieldRecordRoute.LowerName(), HeaderFieldRecordRoute.Abbr:
		header.RecordRoute, err = parseRecordRoute(value, header.RecordRoute)
	case HeaderFieldUserAgent.LowerName(), HeaderFieldUserAgent.Abbr:
		header.UserAgent = value
	case HeaderFieldAuthorization.LowerName(), HeaderFieldAuthorization.Abbr:
		header.Authorization = value
	case HeaderFieldWWWAuthenticate.LowerName(), HeaderFieldWWWAuthenticate.Abbr:
		header.WWWAuthenticate = value
	case HeaderFieldSubject.LowerName(), HeaderFieldSubject.Abbr:
		header.Subject = value
	default:
		header.UnsupportLines = append(header.UnsupportLines, line)
	}
	return
}

// 字符串表达
func (header *Header) String() (result string) {
	// FIXME 采用逗号方式
	for _, via := range header.Via.value {
		result += header.lineString(HeaderFieldVia.Name, via.String())
	}
	for _, route := range header.Route.value {
		result += header.lineString(HeaderFieldRoute.Name, route.String())
	}
	for _, recordRoute := range header.RecordRoute.value {
		result += header.lineString(HeaderFieldRecordRoute.Name, recordRoute.String())
	}
	result += header.lineString(HeaderFieldMaxForwards.Name, header.MaxForwards.String())
	result += header.lineString(HeaderFieldFrom.Name, header.From.String())
	result += header.lineString(HeaderFieldTo.Name, header.To.String())
	result += header.lineString(HeaderFieldCallID.Name, header.CallID)
	result += header.lineString(HeaderFieldCSeq.Name, header.CSeq.String())
	result += header.lineString(HeaderFieldContentLength.Name, fmt.Sprintf("%d", header.ContentLength))
	result += header.lineString(HeaderFieldContentType.Name, header.ContentType)
	if header.Contact != nil {
		result += header.lineString(HeaderFieldContact.Name, header.Contact.String())
	}

	result += header.lineString(HeaderFieldAuthorization.Name, header.Authorization)
	result += header.lineString(HeaderFieldExpires.Name, header.Expires.String())
	result += header.lineString(HeaderFieldUserAgent.Name, header.UserAgent)
	result += header.lineString(HeaderFieldWWWAuthenticate.Name, header.WWWAuthenticate)
	result += header.lineString(HeaderFieldReason.Name, header.Reason)
	result += header.lineString(HeaderFieldSubject.Name, header.Subject)
	for _, line := range header.UnsupportLines {
		result += header.emptyLineString(line)
	}
	return
}

// 单行输出，兼容空行
func (header *Header) lineString(key string, value string) string {
	if len(value) == 0 {
		return ""
	}
	return key + util.COLON + " " + value + util.CRLF
}

func (header *Header) emptyLineString(line string) string {
	return line + util.CRLF
}

func (header *Header) AnalyzeMessage(s []string) (int, error) {
	i := 1
	for ; i < len(s); i++ {
		if 0 == len(s[i]) {
			return i, nil
		}
		err := header.Parse(s[i])
		if err != nil {
			logrus.Errorln("sip处理错误, s : ", s, "err :", err)
			return 0, errors.New("sip处理错误")
		}
	}
	return i, nil
}
